﻿/// <summary>
/// Here are all the methods needed for accessing and processing the XMLs sent and returned
/// from the Live Contacts API in REST
/// Author: Shahal Hazan
/// </summary>

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Xml.Serialization;

namespace LiveConnector
{
    public static class LiveData
    {
        #region const

        private const string LOCATION = "Location";
        private const string DELETE_METHOD = "DELETE";
        private const string baseUri = "https://livecontacts.services.live.com/users/@L@";
        private const string CONTACTS_GET = "/rest/LiveContacts";
        private const string CONTACT_PHONES_GET = "/rest/LiveContacts/Contacts/Contact({0})/Phones";
        
        private const string CONTACT_POST = "/rest/LiveContacts/Contacts";
        private const string CONTACT_PUT = "/rest/LiveContacts/Contacts/Contact({0})";

        private const string PHONE_REQUEST_POST = "/rest/LiveContacts/Contacts/Contact({0})/Phones";
        private const string PHONE_REQUEST_PUT = "/rest/LiveContacts/Contacts/Contact({0})/Phones/Phone({1})";
        private const string EMAIL_REQUEST_POST = "/rest/LiveContacts/Contacts/Contact({0})/Emails";
        private const string EMAIL_REQUEST_PUT = "/rest/LiveContacts/Contacts/Contact({0})/Emails/Email({1})";
        private const string TAG_REQUEST_POST = "/rest/LiveContacts/Tags/Tag({0})/ContactIDs";
        private const string TAG_REQUEST_GET = "/rest/LiveContacts/Tags/Tag({0})";
        private const string TAGS_REQUEST_GET = "/rest/LiveContacts/Tags";
        private const string TAG_REQUEST_DELETE = "/rest/LiveContacts/Tags/Tag({0})/ContactIDs/ContactID/ID({1})";

        #endregion

        #region Contact

        /// <summary>
        /// Gets the contacts.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="id">The id.</param>
        /// <param name="liveCollection">The live contacts.</param>
        /// <param name="error">The error.</param>
        /// <returns>List&lt;LiveConnector.Contact&gt;</returns>
        public static HttpStatusCode GetCollection<T>(string lid, string delegatedToken, string id, out T liveCollection, out string error) where T : LiveCollection, new()
        {
            HttpWebResponse response = null;
            liveCollection = new T();
            error = string.Empty;
            HttpStatusCode httpStatusCode = HttpStatusCode.Unused;
            try
            {
                string uri = string.Empty;
                if (liveCollection is LiveContacts)
                {
                    uri = baseUri + lid + CONTACTS_GET;
                }
                else if (liveCollection is Phones)
                {
                    uri = baseUri + lid + string.Format(CONTACT_PHONES_GET, id);
                }
                else if (liveCollection is Tags)
                {
                    uri = baseUri + lid + TAGS_REQUEST_GET;
                }
                

                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
                //request.UserAgent = "Windows Live Data Interactive SDK";
                request.ContentType = "application/xml; charset=utf-8";
                request.Method = "GET";

                // Add the delegation token to a request header.
                request.Headers.Add("Authorization", "DelegatedToken dt=\"" + delegatedToken + "\"");

                //Issue the HTTP GET request to Windows Live Contacts.
                response = (HttpWebResponse)request.GetResponse();
                httpStatusCode = response.StatusCode;

                XmlSerializer xmlSerializer;
                try
                {
                    xmlSerializer = new XmlSerializer(typeof(T));
                    //using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
                    //{
                    //    string xml = streamReader.ReadToEnd();
                    //}

                    liveCollection = (T)xmlSerializer.Deserialize(new StreamReader(response.GetResponseStream()));
                }
                // Catch an incorrect XML format error
                catch (Exception exception)
                {
                    error = exception.Message;
                }

            }
            catch (WebException webException)
            {
                error = webException.Message;
            }
            finally
            {
                //Close the response.
                if (response != null)
                    response.Close();
            }
            return httpStatusCode;
        }

        /// <summary>
        /// Adds the contact.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="firstName">The first name.</param>
        /// <param name="lastName">The last name.</param>
        /// <param name="phoneNumber">The phone number.</param>
        /// <param name="phoneType"> the phone.</param>
        /// <param name="isDefaultPhoneNumber">if set to <c>true</c> [is default phone number].</param>
        /// <param name="email">The email.</param>
        /// <param name="emailType">Type of the email.</param>
        /// <param name="isDefaultEmailAddress">if set to <c>true</c> [is default email address].</param>
        /// <param name="location">The location.</param>
        /// <returns>String</returns>
        public static string AddContact(string lid, string delegatedToken,
            string firstName, string lastName,
            string phoneNumber, PhoneType phoneType, bool isDefaultPhoneNumber,
            string email, EmailType emailType, bool isDefaultEmailAddress, ref string location)
        {
            Contact contact = new Contact();
            return MakeContactRequest(lid, null, WebRequestMethods.Http.Post, delegatedToken,
            firstName, lastName,
            phoneNumber, phoneType, isDefaultPhoneNumber,
            email, emailType, isDefaultEmailAddress, ref location, ref contact);
        }

        /// <summary>
        /// Updates the contact.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="contactId">The contact id.</param>
        /// <param name="firstName">The first name.</param>
        /// <param name="lastName">The last name.</param>
        /// <returns>String</returns>
        public static string UpdateContact(string lid, string delegatedToken, string contactId,
            string firstName, string lastName)
        {
            string location = string.Empty;
            Contact contact = new Contact();
            return MakeContactRequest(lid, contactId, WebRequestMethods.Http.Put, delegatedToken,
                firstName, lastName,
                null, PhoneType.Other, false,
                null, EmailType.Other, false,
                ref location, ref contact);
        }

        /// <summary>
        /// Deletes the contact.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="contactId">The contact id.</param>
        /// <returns>String</returns>
        public static string DeleteContact(string lid, string delegatedToken, string contactId)
        {
            string location = string.Empty;
            Contact contact = new Contact();
            return MakeContactRequest(lid, contactId, DELETE_METHOD, delegatedToken,
                null, null,
                null, PhoneType.Other, false,
                null, EmailType.Other, false,
                ref location, ref contact);
        }

        /// <summary>
        /// Gets the contact.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="contactId">The contact id.</param>
        /// <returns>String</returns>
        public static string GetContact(string lid, string delegatedToken, string contactId)
        {
            string location = string.Empty;
            Contact contact = new Contact();
            return MakeContactRequest(lid, contactId, WebRequestMethods.Http.Get, delegatedToken,
                null, null,
                null, PhoneType.Other, false,
                null, EmailType.Other, false,
                ref location, ref contact);
        }

        /// <summary>
        /// Makes the contact request.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="contactID">The contact ID.</param>
        /// <param name="method">The method.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="firstName">The first name.</param>
        /// <param name="lastName">The last name.</param>
        /// <param name="phoneNumber">The phone number.</param>
        /// <param name="phoneType">the phone.</param>
        /// <param name="isDefaultPhoneNumber">if set to <c>true</c> [is default phone number].</param>
        /// <param name="email">The email.</param>
        /// <param name="emailType">Type of the email.</param>
        /// <param name="isDefaultEmailAddress">if set to <c>true</c> [is default email address].</param>
        /// <param name="location">The location.</param>
        /// <param name="contact">The live contacts contact.</param>
        /// <returns>String</returns>
        private static string MakeContactRequest(
            string lid, string contactID, string method, string delegatedToken,
            string firstName, string lastName,
            string phoneNumber, PhoneType phoneType, bool isDefaultPhoneNumber,
            string email, EmailType emailType, bool isDefaultEmailAddress, ref string location, ref Contact contact)
        {
            // Create the request.
            string uri;
            if (method == WebRequestMethods.Http.Post)
            {
                uri = baseUri + lid + CONTACT_POST;
            }
            else // PUT, DELETE
            {
                uri = baseUri + lid + string.Format(CONTACT_PUT, contactID);
            }

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
            //request.UserAgent = "Windows Live Data Interactive SDK";
            request.Method = method;
            request.ContentType = "application/xml; charset=utf-8";

            // Put the domain token into a request header.
            request.Headers.Add("Authorization", "DelegatedToken dt=\"" + delegatedToken + "\"");

            string serializedXML = null;
            if (method == WebRequestMethods.Http.Put || method == WebRequestMethods.Http.Post)
            {
                if (method == WebRequestMethods.Http.Post)
                {
                    // Create the ignored attributes
                    XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
                    GetAttrOverrides(typeof (Contact),
                                     new List<KeyValuePair<Type, string>>
                                         {
                                             new KeyValuePair<Type, string>(typeof (string), "ID"),
                                             new KeyValuePair<Type, string>(typeof (string), "CID"),
                                             new KeyValuePair<Type, string>(typeof (string), "AutoUpdateEnabled"),
                                             new KeyValuePair<Type, string>(typeof (string), "AutoUpdateStatus"),
                                             new KeyValuePair<Type, string>(typeof (string), "WindowsLiveID"),
                                         }, ref attrOverrides);


                    string phoneTypeString = Enum.GetName(typeof (PhoneType), phoneType);
                    // Create the Phone class
                    ContactPhone contactPhone = new ContactPhone
                                                                            {
                                                                                PhoneType = phoneTypeString,
                                                                                Number = phoneNumber,
                                                                                IsDefault = isDefaultPhoneNumber
                                                                            };

                    GetAttrOverrides(typeof(ContactPhone),
                                     new List<KeyValuePair<Type, string>>
                                         {
                                             new KeyValuePair<Type, string>(typeof (bool), "IsIMEnabled")

                                         }, ref attrOverrides);

                    string emailTypeString = Enum.GetName(typeof(EmailType), emailType);
                    // Create the Email class
                    ContactEmail contactEmail = new ContactEmail
                                                                            {
                                                                                EmailType = emailTypeString,
                                                                                Address = email,
                                                                                IsDefault = isDefaultEmailAddress
                                                                            };

                    GetAttrOverrides(typeof(ContactEmail),
                                     new List<KeyValuePair<Type, string>>
                                         {
                                             new KeyValuePair<Type, string>(typeof (bool), "IsIMEnabled")

                                         }, ref attrOverrides);

                    // Create the Contact class
                    Contact liveContact =
                        new Contact
                            {
                                Phones = new[] {contactPhone},
                                Emails = new[] {contactEmail},
                                Profiles = new ContactProfiles
                                               {
                                                   Personal =
                                                       new ContactProfilesPersonal
                                                           {
                                                               FirstName = firstName,
                                                               LastName = lastName
                                                           }
                                               }
                            };


                    serializedXML =
                        new XmlSerializer(typeof (Contact), attrOverrides).SerializeXMLToString(liveContact);
                }
                else if (method == WebRequestMethods.Http.Put)
                {
                    // Create the ignored attributes
                    XmlAttributeOverrides ignoredAttributes = new XmlAttributeOverrides();
                    GetAttrOverrides(typeof(Contact),
                                     new List<KeyValuePair<Type, string>>
                                         {
                                             new KeyValuePair<Type, string>(typeof (string), "ID"),
                                             new KeyValuePair<Type, string>(typeof (string), "CID"),
                                             new KeyValuePair<Type, string>(typeof (string), "AutoUpdateEnabled"),
                                             new KeyValuePair<Type, string>(typeof (string), "AutoUpdateStatus"),
                                             new KeyValuePair<Type, string>(typeof (string), "WindowsLiveID"),
                                         }, ref ignoredAttributes);

                    // Create the Contact class
                    Contact liveContact =
                        new Contact
                        {
                            Profiles = new ContactProfiles
                            {
                                Personal =
                                    new ContactProfilesPersonal
                                    {
                                        FirstName = firstName,
                                        LastName = lastName
                                    }
                            }
                        };


                    serializedXML =
                        new XmlSerializer(typeof(Contact), ignoredAttributes).SerializeXMLToString(liveContact);
                }

                // Encode the XML data into a byte stream.
                byte[] byteArray = null;
                //ASCIIEncoding encoding = new ASCIIEncoding();
                if (!string.IsNullOrEmpty(serializedXML))
                    byteArray = Encoding.UTF8.GetBytes(serializedXML);

                if (byteArray != null)
                {
                    using (Stream newStream = request.GetRequestStream())
                    {
                        newStream.Write(byteArray, 0, byteArray.Length);
                    }
                }
            }
            // Issue the HTTP request to Windows Live Contacts.
            string result;
            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
                if (method == "GET")
                {
                    XmlSerializer xmlSerializer;
                    try
                    {
                        xmlSerializer = new XmlSerializer(typeof(Contact));
                        contact = (Contact)xmlSerializer.Deserialize(new StreamReader(response.GetResponseStream()));
                    }
                    // Catch an incorrect XML format error
                    catch (Exception exception)
                    {
                        result = exception.Message;
                        return result;
                    }
                }
                // Update the label with the status code.
                else if (method == WebRequestMethods.Http.Post)
                {
                    location = response.Headers[LOCATION];
                }

                result = response.StatusCode.ToString();
            }
            catch (WebException ex)
            {
                return ex.Message;
            }
            finally
            {
                if (response != null)
                    response.Close();
            }
            return result;
        }

        #endregion
        
        #region Phone

        /// <summary>
        /// Adds the contact phone.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="contactId">The contact id.</param>
        /// <param name="phoneNumber">The phone number.</param>
        /// <param name="phoneType"> the phone.</param>
        /// <param name="isDefault">if set to <c>true</c> [is default].</param>
        /// <param name="location">The location.</param>
        /// <returns>String</returns>
        public static string AddContactPhone(string lid, string delegatedToken, string contactId, string phoneNumber, PhoneType phoneType, bool isDefault, ref string location)
        {
            ContactPhone phone = new ContactPhone();
            return MakeRequest<ContactPhone, PhoneType>(lid, contactId, WebRequestMethods.Http.Post, delegatedToken, phoneNumber, phoneType, isDefault, string.Empty, ref location, ref phone);
        }

        /// <summary>
        /// Updates the contact phone.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="contactId">The contact id.</param>
        /// <param name="phoneNumber">The phone number.</param>
        /// <param name="phoneId">The phone id.</param>
        /// <param name="isDefault">if set to <c>true</c> [is default].</param>
        /// <returns>String</returns>
        public static string UpdateContactPhone(string lid, string delegatedToken, string contactId, string phoneNumber, string phoneId, bool isDefault)
        {
            string location = string.Empty;
            ContactPhone phone = new ContactPhone();
            return MakeRequest<ContactPhone, PhoneType>(lid, contactId, WebRequestMethods.Http.Put, delegatedToken, phoneNumber, PhoneType.Other, isDefault, phoneId, ref location, ref phone);
        }

        /// <summary>
        /// Deletes the contact phone.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="contactId">The contact id.</param>
        /// <param name="phoneId">The phone id.</param>
        /// <returns>String</returns>
        public static string DeleteContactPhone(string lid, string delegatedToken, string contactId, string phoneId)
        {
            string location = string.Empty;
            ContactPhone phone = new ContactPhone();
            return MakeRequest<ContactPhone, PhoneType>(lid, contactId, DELETE_METHOD, delegatedToken, string.Empty, PhoneType.Other, false, phoneId, ref location, ref phone);
        }

        /// <summary>
        /// Gets the contact phone.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="contactId">The contact id.</param>
        /// <param name="phoneId">The phone id.</param>
        /// <param name="phone">The phone.</param>
        /// <returns>String</returns>
        public static string GetContactPhone(string lid, string delegatedToken, string contactId, string phoneId, ref ContactPhone phone)
        {
            string location = string.Empty;
            return MakeRequest<ContactPhone, PhoneType>(lid, contactId, WebRequestMethods.Http.Get, delegatedToken, string.Empty, PhoneType.Other, false, phoneId, ref location, ref phone);
        }

        /// <summary>
        /// Gets the serialized XML phone put.
        /// </summary>
        /// <param name="ignoredAttributes">The ignored attributes.</param>
        /// <param name="phoneNumber">The phone number.</param>
        /// <param name="isDefault">if set to <c>true</c> [is default].</param>
        /// <returns>String</returns>
        private static string GetSerializedXMLPhonePut(XmlAttributeOverrides ignoredAttributes, string phoneNumber, bool isDefault)
        {
            // Create the ignored attributes
            GetAttrOverrides(typeof (ContactPhone),
                             new List<KeyValuePair<Type, string>>
                                 {
                                     new KeyValuePair<Type, string>(typeof (string), "PhoneType"),
                                     new KeyValuePair<Type, string>(typeof (bool), "IsIMEnabled")
                                 }, ref ignoredAttributes);

            // Create the Phone class
            ContactPhone contactPhone = new ContactPhone
                                            {
                                                Number = phoneNumber,
                                                IsDefault = isDefault
                                            };
            string serializedXML = new XmlSerializer(typeof(ContactPhone), ignoredAttributes).SerializeXMLToString(
                contactPhone);
            return serializedXML;
        }

        /// <summary>
        /// Gets the serialized XML phone post.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ignoredAttributes">The ignored attributes.</param>
        /// <param name="phoneType">Type of the phone.</param>
        /// <param name="phoneNumber">The phone number.</param>
        /// <param name="isDefault">if set to <c>true</c> [is default].</param>
        /// <returns>String</returns>
        private static string GetSerializedXMLPhonePost<T>(XmlAttributeOverrides ignoredAttributes, T phoneType, string phoneNumber, bool isDefault)
        {
            // Create the ignored attributes
            GetAttrOverrides(typeof (ContactPhone),
                             new List<KeyValuePair<Type, string>>
                                 {
                                     new KeyValuePair<Type, string>(typeof (bool), "IsIMEnabled")
                                 }, ref ignoredAttributes);

            string phoneTypeString = Enum.GetName(typeof(PhoneType), phoneType);
            // Create the Phone class
            ContactPhone contactPhone = new ContactPhone
                                            {
                                                PhoneType = phoneTypeString,
                                                Number = phoneNumber,
                                                IsDefault = isDefault
                                            };
            string serializedXML = new XmlSerializer(typeof(ContactPhone), ignoredAttributes).SerializeXMLToString(
                contactPhone);
            return serializedXML;
        }

        #endregion

        #region Email

        /// <summary>
        /// Adds the contact email.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="contactId">The contact id.</param>
        /// <param name="email">The email.</param>
        /// <param name="emailType">Type of the email.</param>
        /// <param name="isDefault">if set to <c>true</c> [is default].</param>
        /// <param name="location">The location.</param>
        /// <returns>String</returns>
        public static string AddContactEmail(string lid, string delegatedToken, string contactId, string email, EmailType emailType, bool isDefault, ref string location)
        {
            ContactEmail contactEmail = new ContactEmail();
            return MakeRequest<ContactEmail, EmailType>(lid, contactId, WebRequestMethods.Http.Post, delegatedToken, email, emailType, isDefault, string.Empty, ref location, ref contactEmail);
        }

        /// <summary>
        /// Updates the contact email.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="contactId">The contact id.</param>
        /// <param name="email">The email.</param>
        /// <param name="emailId">The email id.</param>
        /// <param name="isDefault">if set to <c>true</c> [is default].</param>
        /// <returns>String</returns>
        public static string UpdateContactEmail(string lid, string delegatedToken, string contactId, string email, string emailId, bool isDefault)
        {
            string location = string.Empty;
            ContactEmail contactEmail = new ContactEmail();
            return MakeRequest<ContactEmail, EmailType>(lid, contactId, WebRequestMethods.Http.Put, delegatedToken, email, EmailType.Other, isDefault, emailId, ref location, ref contactEmail);
        }

        /// <summary>
        /// Deletes the contact email.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="contactId">The contact id.</param>
        /// <param name="emailId">The email id.</param>
        /// <returns>String</returns>
        public static string DeleteContactEmail(string lid, string delegatedToken, string contactId, string emailId)
        {
            string location = string.Empty;
            ContactEmail contactEmail = new ContactEmail();
            return MakeRequest<ContactEmail, EmailType>(lid, contactId, DELETE_METHOD, delegatedToken, string.Empty, EmailType.Other, false, emailId, ref location, ref contactEmail);
        }

        /// <summary>
        /// Gets the contact email.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="contactId">The contact id.</param>
        /// <param name="emailId">The email id.</param>
        /// <param name="contactEmail">The live contacts contact email.</param>
        /// <returns>String</returns>
        public static string GetContactEmail(string lid, string delegatedToken, string contactId, string emailId, ref ContactEmail contactEmail)
        {
            string location = string.Empty;
            return MakeRequest<ContactEmail, EmailType>(lid, contactId, WebRequestMethods.Http.Get, delegatedToken, string.Empty, EmailType.Other, false, emailId, ref location, ref contactEmail);
        }

        /// <summary>
        /// Gets the serialized XML email put.
        /// </summary>
        /// <param name="ignoredAttributes">The ignored attributes.</param>
        /// <param name="address">The address.</param>
        /// <param name="isDefault">if set to <c>true</c> [is default].</param>
        /// <returns>String</returns>
        private static string GetSerializedXMLEmailPut(XmlAttributeOverrides ignoredAttributes, string address, bool isDefault)
        {
            // Create the ignored attributes
            GetAttrOverrides(typeof(ContactEmail),
                             new List<KeyValuePair<Type, string>>
                                 {
                                     new KeyValuePair<Type, string>(typeof (string), "EmailType"),
                                     new KeyValuePair<Type, string>(typeof (bool), "IsIMEnabled")
                                 }, ref ignoredAttributes);

            // Create the Email class
            ContactEmail contactEmail = new ContactEmail
                                                                    {
                                                                        Address = address,
                                                                        IsDefault = isDefault
                                                                    };
            string serializedXML = new XmlSerializer(typeof(ContactEmail), ignoredAttributes).SerializeXMLToString(
                contactEmail);
            return serializedXML;
        }

        /// <summary>
        /// Gets the serialized XML email post.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ignoredAttributes">The ignored attributes.</param>
        /// <param name="emailType">Type of the email.</param>
        /// <param name="address">The address.</param>
        /// <returns>String</returns>
        private static string GetSerializedXMLEmailPost<T>(XmlAttributeOverrides ignoredAttributes, T emailType, string address)
        {
            // Create the ignored attributes
            GetAttrOverrides(typeof(ContactEmail),
                             new List<KeyValuePair<Type, string>>
                                 {
                                     new KeyValuePair<Type, string>(typeof (bool), "IsDefault"),
                                     new KeyValuePair<Type, string>(typeof (bool), "IsIMEnabled")
                                 }, ref ignoredAttributes);

            string emailTypeString = Enum.GetName(typeof(EmailType), emailType);
            // Create the Email class
            ContactEmail contactEmail = new ContactEmail
                                                                    {
                                                                        EmailType = emailTypeString,
                                                                        Address = address
                                                                    };
            string serializedXML = new XmlSerializer(typeof(ContactEmail), ignoredAttributes).SerializeXMLToString(
                contactEmail);
            return serializedXML;
        }

        #endregion

        #region Tag

        /// <summary>
        /// Adds the contact to tag.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="tagId">The tag id.</param>
        /// <param name="contactId">The contact id.</param>
        /// <param name="location">The location.</param>
        /// <returns>String</returns>
        public static string AddContactToTag(string lid, string delegatedToken, string tagId, string contactId, ref string location)
        {
            LiveTag liveTag = new LiveTag();
            return MakeRequest<LiveTag, string>(lid, contactId, WebRequestMethods.Http.Post, delegatedToken,
                tagId, string.Empty, false, string.Empty, ref location, ref liveTag);
        }

        /// <summary>
        /// Deletes the contact from tag.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="tagId">The tag id.</param>
        /// <param name="contactId">The contact id.</param>
        /// <returns>String</returns>
        public static string DeleteContactFromTag(string lid, string delegatedToken, string tagId, string contactId)
        {
            string location = string.Empty;
            LiveTag liveTag = new LiveTag();
            return MakeRequest<LiveTag, string>(lid, contactId, DELETE_METHOD, delegatedToken,
                tagId, string.Empty, false, string.Empty, ref location, ref liveTag);
        }

        /// <summary>
        /// Gets the tag contactIDs.
        /// </summary>
        /// <param name="lid">The lid.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="tagId">The tag id.</param>
        /// <param name="contactID">The contact ID.</param>
        /// <param name="liveTag">The live contacts tag.</param>
        /// <returns>String</returns>
        public static string GetTagContactID(string lid, string delegatedToken, string tagId, string contactID, ref LiveTag liveTag)
        {
            string location = string.Empty;
            return MakeRequest<LiveTag, string>(lid, contactID, WebRequestMethods.Http.Get, delegatedToken,
                tagId, string.Empty, false, string.Empty, ref location, ref liveTag);
        }

        /// <summary>
        /// Gets the serialized XML tag post.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ignoredAttributes">The ignored attributes.</param>
        /// <param name="contactId">The contact id.</param>
        /// <returns>String</returns>
        private static string GetSerializedXMLTagPost(string contactId)
        {
            return string.Format("<ContactID><ID>{0}</ID></ContactID>", contactId);
        }

        #endregion

        #region helper methods

        /// <summary>
        /// Makes the request for contact phone: Create, Update or Delete requests
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="U"></typeparam>
        /// <param name="lid">The lid.</param>
        /// <param name="contactID">The contact ID.</param>
        /// <param name="method">The method.</param>
        /// <param name="delegatedToken">The delegated token.</param>
        /// <param name="value">The contact info.</param>
        /// <param name="elementType">Type of the phone.</param>
        /// <param name="isDefault">if set to <c>true</c> [is default].</param>
        /// <param name="valueId">The id - only needed for updating a number</param>
        /// <param name="location">The location.</param>
        /// <param name="t">The t.</param>
        /// <returns>String</returns>
        private static string MakeRequest<T, U>(string lid, string contactID, string method, string delegatedToken,
            string value, U elementType, bool isDefault, string valueId,
            ref string location, ref T t) where T : LiveContactElement
        {
            location = string.Empty;
            // Create the request.
            string uri = string.Empty;
            if (method == WebRequestMethods.Http.Post)
            {
                if (t is ContactPhone)
                {
                    uri = baseUri + lid + string.Format(PHONE_REQUEST_POST, contactID);
                }
                else if (t is ContactEmail)
                {
                uri = baseUri + lid + string.Format(EMAIL_REQUEST_POST, contactID);
                }                
                else if (t is LiveTag)
                {
                    uri = baseUri + lid + string.Format(TAG_REQUEST_POST, value);
                }
            }
            else // PUT, DELETE, GET
            {
                if (t is ContactPhone)
                {
                    uri = baseUri + lid + string.Format(PHONE_REQUEST_PUT, contactID, valueId);
                }
                else if (t is ContactEmail)
                {
                    uri = baseUri + lid + string.Format(EMAIL_REQUEST_PUT, contactID, valueId);
                }
                //ContactID: 128 Bit Decimal.
                // Unique ID of the contact belonging to this group.
                // ContactID elements may only be inserted or deleted.
                // They cannot be individually updated.
                // DELETE, GET
                else if (t is LiveTag)
                {
                    if (method == WebRequestMethods.Http.Get)
                        uri = baseUri + lid + string.Format(TAG_REQUEST_GET, value);
                    else
                        uri = baseUri + lid + string.Format(TAG_REQUEST_DELETE, value, contactID);
                }
            }

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
            //request.UserAgent = "Windows Live Data Interactive SDK";
            request.Method = method;
            request.ContentType = "application/xml; charset=utf-8";

            // Put the domain token into a request header.
            request.Headers.Add("Authorization", "DelegatedToken dt=\"" + delegatedToken + "\"");

            string serializedXML = null;
            if (method == WebRequestMethods.Http.Put || method == WebRequestMethods.Http.Post)
            {
                XmlAttributeOverrides ignoredAttributes = new XmlAttributeOverrides();
                if (method == WebRequestMethods.Http.Post)
                {
                    if (t is ContactPhone)
                    {
                        serializedXML = GetSerializedXMLPhonePost(ignoredAttributes, elementType, value, isDefault);
                    }
                    else if (t is ContactEmail)
                    {
                        serializedXML = GetSerializedXMLEmailPost(ignoredAttributes, elementType, value);
                    }
                    // Here we add the contact ID to the correct Tag
                    else if (t is LiveTag)
                    {
                        serializedXML = GetSerializedXMLTagPost(contactID);
                    }
                }
                else if (method == WebRequestMethods.Http.Put)
                {
                    if (t is ContactPhone)
                    {
                        serializedXML = GetSerializedXMLPhonePut(ignoredAttributes, value, isDefault);
                    }
                    else if (t is ContactEmail)
                    {
                        serializedXML = GetSerializedXMLEmailPut(ignoredAttributes, value, isDefault);
                    }
                }

                // Encode the XML data into a byte stream.
                byte[] byteArray = null;
                if (!string.IsNullOrEmpty(serializedXML))
                    byteArray = Encoding.UTF8.GetBytes(serializedXML);

                if (byteArray != null)
                {
                    using (Stream newStream = request.GetRequestStream())
                    {
                        newStream.Write(byteArray, 0, byteArray.Length);
                    }
                }

            }
            // Issue the HTTP request to Windows Live Contacts.
            string result;
            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
                if (method == "GET")
                {
                    //using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
                    //{
                    //    string xml = streamReader.ReadToEnd();
                    //}
                    XmlSerializer xmlSerializer;
                    try
                    {
                        xmlSerializer = new XmlSerializer(typeof(T));
                        t = (T)xmlSerializer.Deserialize(new StreamReader(response.GetResponseStream()));
                    }
                    // Catch an incorrect XML format error
                    catch (Exception exception)
                    {
                        result = exception.Message;
                        return result;
                    }
                }
                // Update the label with the status code.
                else if (method == WebRequestMethods.Http.Post)
                {
                    location = response.Headers[LOCATION];
                }
                result = response.StatusCode.ToString();
            }
            catch (WebException ex)
            {
                result = ex.Message;
                return result;
            }
            finally
            {
                if (response != null)
                    response.Close();
            }
            return result;
        }

        /// <summary>
        /// Gets the attr overrides.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="toBeIgnored">To be ignored.</param>
        /// <param name="attrOverrides">The attr overrides.</param>
        /// <returns>XmlAttributeOverrides</returns>
        private static void GetAttrOverrides(Type type, IEnumerable<KeyValuePair<Type, string>> toBeIgnored, ref XmlAttributeOverrides attrOverrides)
        {
            // Create the XmlAttributeOverrides object.
            //XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();

            // Each overridden field, property, or type requires an XmlAttributes object.
            XmlAttributes xmlAttributes = new XmlAttributes { XmlIgnore = true };

            foreach (KeyValuePair<Type, string> list in toBeIgnored)
            {
                // Create an XmlElementAttribute to override the 
                // field that returns Instrument objects. The overridden field
                // returns Brass objects instead.
                XmlElementAttribute xmlElementAttribute =
                    new XmlElementAttribute
                    {
                        ElementName = list.Value,
                        Type = list.Key
                    };
                // Add the element to the collection of elements.
                xmlAttributes.XmlElements.Add(xmlElementAttribute);

                // Add the type of the class that contains the overridden 
                // member and the XmlAttributes to override it with to the 
                // XmlAttributeOverrides object.
                attrOverrides.Add(type, list.Value, xmlAttributes);
            }
            return;
        }

        /// <summary>
        /// Serializes to string.
        /// </summary>
        /// <param name="xmlSerializer">The XML serializer.</param>
        /// <param name="_object">The _object.</param>
        /// <returns>String</returns>
        private static string SerializeXMLToString(this XmlSerializer xmlSerializer, object _object)
        {
            // to suppress unused default namespace entries in the root elt
            XmlSerializerNamespaces _ns = new XmlSerializerNamespaces();
            _ns.Add("", "");

            var builder = new StringBuilder();
            var settings = new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true, Indent = false };

            using (var writer = System.Xml.XmlWriter.Create(builder, settings))
            {
                if (writer != null) xmlSerializer.Serialize(writer, _object, _ns);
            }
            return builder.ToString();
        }

        #endregion

    }
}
